package com.bf.electroplating.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bf.electroplating.mapper.ViewAccessDeviceListMapper;
import com.bf.electroplating.pojo.dto.viewAccessDevice.ValveStatusDetailVO;
import com.bf.electroplating.pojo.dto.viewAccessDevice.ValveStatusVO;
import com.bf.electroplating.pojo.entity.ViewAccessDeviceList;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessDeviceCompanyChartVO;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessDeviceCompanyQueryDTO;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessDeviceCompanyStatsVO;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessDeviceTypeQueryDTO;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessDeviceTypeVO;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessInstrumentTypeQueryDTO;
import com.bf.electroplating.pojo.vo.viewAccessDeviceList.ViewAccessInstrumentTypeVO;
import com.bf.electroplating.service.IViewAccessDeviceListService;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * VIEW 服务实现类
 * </p>
 *
 * @author gzd
 * @since 2025-11-12
 */
@Service
public class ViewAccessDeviceListServiceImpl extends ServiceImpl<ViewAccessDeviceListMapper, ViewAccessDeviceList> implements IViewAccessDeviceListService {

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public List<ViewAccessDeviceTypeVO> listDeviceTypes() {
        List<ViewAccessDeviceList> records = fetchRecords(
                null,
                null,
                null,
                null,
                null
        );

        if (records.isEmpty()) {
            return Collections.emptyList();
        }

        Map<Long, List<ViewAccessDeviceList>> grouped = records.stream()
                .filter(item -> item.getClassId() != null)
                .collect(Collectors.groupingBy(ViewAccessDeviceList::getClassId, LinkedHashMap::new, Collectors.toList()));

        List<ViewAccessDeviceTypeVO> voList= grouped.entrySet().stream()
                .map(entry -> {
                    Long classId = entry.getKey();
                    List<ViewAccessDeviceList> list = entry.getValue();
                    ViewAccessDeviceTypeVO vo = new ViewAccessDeviceTypeVO();
                    vo.setClassId(classId);
                    vo.setClassLabel(firstNonEmpty(list, ViewAccessDeviceList::getClassLabel));
                    vo.setInstrumentTypeCount(distinctCount(list, ViewAccessDeviceList::getDeviceId));
                    vo.setCompanyCount(distinctCount(list, ViewAccessDeviceList::getCompanyId, this::hasText));
                    vo.setDeviceCount(sumDeviceCount(list));
                    return vo;
                })
                .sorted(Comparator.comparing(ViewAccessDeviceTypeVO::getClassId, Comparator.nullsLast(Long::compareTo)))
                .collect(Collectors.toList());
        return voList;
    }

    @Override
    public List<ViewAccessInstrumentTypeVO> listInstrumentTypes(ViewAccessInstrumentTypeQueryDTO query) {
        if (query == null || query.getClassId() == null) {
            return Collections.emptyList();
        }

        List<ViewAccessDeviceList> records = fetchRecords(
                null,
                null,
                null,
                query.getClassId(),
                null
        );

        if (records.isEmpty()) {
            return Collections.emptyList();
        }

        Map<Long, List<ViewAccessDeviceList>> grouped = records.stream()
                .filter(item -> item.getDeviceId() != null)
                .collect(Collectors.groupingBy(ViewAccessDeviceList::getDeviceId, LinkedHashMap::new, Collectors.toList()));

        List<ViewAccessInstrumentTypeVO>  voList= grouped.entrySet().stream()
                .map(entry -> {
                    Long deviceId = entry.getKey();
                    List<ViewAccessDeviceList> list = entry.getValue();
                    ViewAccessInstrumentTypeVO vo = new ViewAccessInstrumentTypeVO();
                    vo.setClassId(query.getClassId());
                    vo.setClassLabel(firstNonEmpty(list, ViewAccessDeviceList::getClassLabel));
                    vo.setDeviceId(deviceId);
                    vo.setDeviceLabel(firstNonEmpty(list, ViewAccessDeviceList::getDeviceLabel));
                    vo.setMonitoringFactor(firstNonEmpty(list, ViewAccessDeviceList::getMonitoringFactor));
                    vo.setMonitoringName(firstNonEmpty(list, ViewAccessDeviceList::getMonitoringName));
                    vo.setValueUnit(firstNonEmpty(list, ViewAccessDeviceList::getValueUnit));
                    vo.setCompanyCount(distinctCount(list, ViewAccessDeviceList::getCompanyId, this::hasText));
                    vo.setDeviceCount(sumDeviceCount(list));
                    return vo;
                })
                .sorted(Comparator.comparing(ViewAccessInstrumentTypeVO::getDeviceId, Comparator.nullsLast(Long::compareTo)))
                .collect(Collectors.toList());
        return voList;
    }

    @Override
    public ViewAccessDeviceCompanyStatsVO getCompanyStatistics(ViewAccessDeviceCompanyQueryDTO query) {
        List<ViewAccessDeviceList> records = fetchRecords(
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getRootNode).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getLeafNode).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getCompanyId).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getClassId).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getDeviceId).orElse(null)
        );

        ViewAccessDeviceCompanyStatsVO result = new ViewAccessDeviceCompanyStatsVO();
        if (records.isEmpty()) {
            return result;
        }

        List<ViewAccessDeviceCompanyStatsVO.CompanyItem> companyItems = buildCompanyItemsByCompanyName(records);
        long deviceTotal = companyItems.stream()
                .map(ViewAccessDeviceCompanyStatsVO.CompanyItem::getDeviceCount)
                .filter(Objects::nonNull)
                .mapToLong(Long::longValue)
                .sum();

        long companyCount = companyItems.size();
        long activeCompanyCount = companyItems.stream()
                .filter(item -> hasText(item.getNowValue()) || hasText(item.getMonitoringTime()))
                .count();

        result.setClassId(firstNonNull(records, ViewAccessDeviceList::getClassId));
        result.setClassLabel(firstNonEmpty(records, ViewAccessDeviceList::getClassLabel));
        result.setDeviceId(firstNonNull(records, ViewAccessDeviceList::getDeviceId));
        result.setDeviceLabel(firstNonEmpty(records, ViewAccessDeviceList::getDeviceLabel));
        result.setDeviceCount(deviceTotal);
        result.setCompanyCount(companyCount);
        result.setActiveCompanyCount(activeCompanyCount);
        result.setInactiveCompanyCount(Math.max(companyCount - activeCompanyCount, 0));
        result.setCompanyList(companyItems);

        return result;
    }

    @Override
    public List<ViewAccessDeviceCompanyChartVO> listCompanyChart(ViewAccessDeviceCompanyQueryDTO query) {
        List<ViewAccessDeviceList> records = fetchRecords(
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getRootNode).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getLeafNode).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getCompanyId).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getClassId).orElse(null),
                Optional.ofNullable(query).map(ViewAccessDeviceCompanyQueryDTO::getDeviceId).orElse(null)
        );

        if (records.isEmpty()) {
            return Collections.emptyList();
        }

        List<ViewAccessDeviceCompanyStatsVO.CompanyItem> companyItems = buildCompanyItems(records);
        return  companyItems.stream()
                .filter(item -> isZeroValue(item.getNowValue()))
                .map(item -> {
                    ViewAccessDeviceCompanyChartVO vo = new ViewAccessDeviceCompanyChartVO();
                    vo.setCompanyId(item.getCompanyId());
                    vo.setCompanyName(item.getCompanyName());
                    vo.setCompanyAbbreviation(item.getContrastLabel());
                    vo.setDeviceCount(item.getDeviceCount());
                    vo.setNowValue(item.getNowValue());
                    vo.setValueUnit(item.getValueUnit());
                    vo.setMonitoringTime(item.getMonitoringTime());
                    return vo;
                })
                .sorted(Comparator.comparing(ViewAccessDeviceCompanyChartVO::getDeviceCount, Comparator.nullsLast(Long::compareTo)).reversed())
                .collect(Collectors.toList());
    }

    @Override
    public ValveStatusVO valveStatus(ViewAccessDeviceCompanyQueryDTO queryDTO) {
        List<ViewAccessDeviceList> records = fetchRecords(
                Optional.ofNullable(queryDTO).map(ViewAccessDeviceCompanyQueryDTO::getRootNode).orElse(null),
                Optional.ofNullable(queryDTO).map(ViewAccessDeviceCompanyQueryDTO::getLeafNode).orElse(null),
                Optional.ofNullable(queryDTO).map(ViewAccessDeviceCompanyQueryDTO::getCompanyId).orElse(null),
                Optional.ofNullable(queryDTO).map(ViewAccessDeviceCompanyQueryDTO::getClassId).orElse(null),
                Optional.ofNullable(queryDTO).map(ViewAccessDeviceCompanyQueryDTO::getDeviceId).orElse(null)
        );
        ValveStatusVO valveStatusVO = new ValveStatusVO();
        if (records.isEmpty()) {
            return valveStatusVO;
        }
        if (!CollectionUtils.isEmpty(records)) {
            List<ValveStatusDetailVO> leftList = records.stream().filter(i->i.getDeviceCount()!=null&&i.getDeviceCount()>0&&("雨排口阀门".equals(i.getMonitoringName())||"监控摄像机".equals(i.getMonitoringName()))).map(i->{
                ValveStatusDetailVO vo = new ValveStatusDetailVO();
                BeanUtils.copyProperties(i,vo);
                vo.setName(i.getContrastLabel());
                vo.setType(i.getMonitoringName());
                vo.setStatus(i.getNowValue());
                return vo;
            }).collect(Collectors.toList());
            valveStatusVO.setLeftList(leftList);
            List<ValveStatusDetailVO> right = records.stream().filter(i->i.getDeviceCount()!=null&&i.getDeviceCount()>0&&"应急池阀门".equals(i.getMonitoringName())).map(i->{
                ValveStatusDetailVO vo = new ValveStatusDetailVO();
                BeanUtils.copyProperties(i,vo);
                vo.setName(i.getContrastLabel());
                vo.setStatus(i.getNowValue());
                vo.setType(i.getMonitoringName());
                return vo;
            }).collect(Collectors.toList());
            valveStatusVO.setRightList(right);
        }
        //摄像头分左右
        if (!CollectionUtils.isEmpty(valveStatusVO.getLeftList())&&"监控摄像机".equals(valveStatusVO.getLeftList().get(0).getType())) {
            List<ValveStatusDetailVO> leftList=valveStatusVO.getLeftList();
            List<ValveStatusDetailVO> rightList=new ArrayList<>();
            List<ValveStatusDetailVO> newLeftList=new ArrayList<>();
            for (int i=0;i<leftList.size();i++) {
                if (i%2==0) {
                    newLeftList.add(leftList.get(i));
                }else{
                    rightList.add(leftList.get(i));
                }
            }
            valveStatusVO.setLeftList(newLeftList);
            valveStatusVO.setRightList(rightList);
        }
        return valveStatusVO;
    }

    private List<ViewAccessDeviceList> fetchRecords(String rootNode, String leafNode, String companyId, Long classId, Long deviceId) {
        LambdaQueryWrapper<ViewAccessDeviceList> wrapper = Wrappers.lambdaQuery();
        if (hasText(rootNode)) {
            wrapper.eq(ViewAccessDeviceList::getRootNode, rootNode);
        }
        if (hasText(leafNode)) {
            wrapper.eq(ViewAccessDeviceList::getLeafNode, leafNode);
        }
        if (hasText(companyId)) {
            wrapper.eq(ViewAccessDeviceList::getCompanyId, companyId);
        }
        if (classId != null) {
            wrapper.eq(ViewAccessDeviceList::getClassId, classId);
        }
        if (deviceId != null) {
            wrapper.eq(ViewAccessDeviceList::getDeviceId, deviceId);
        }
        wrapper.orderByAsc(ViewAccessDeviceList::getClassId, ViewAccessDeviceList::getDeviceId, ViewAccessDeviceList::getCompanyName);
        return this.list(wrapper);
    }

    private List<ViewAccessDeviceCompanyStatsVO.CompanyItem> buildCompanyItems(List<ViewAccessDeviceList> records) {
        if (records.isEmpty()) {
            return Collections.emptyList();
        }

        Map<String, List<ViewAccessDeviceList>> groupedByCompany = records.stream()
                .collect(Collectors.groupingBy(this::buildCompanyKey, LinkedHashMap::new, Collectors.toList()));

        List<ViewAccessDeviceCompanyStatsVO.CompanyItem> result = new ArrayList<>();
        for (List<ViewAccessDeviceList> companyRecords : groupedByCompany.values()) {
            if (companyRecords.isEmpty()) {
                continue;
            }
            ViewAccessDeviceList first = companyRecords.get(0);
            ViewAccessDeviceCompanyStatsVO.CompanyItem item = new ViewAccessDeviceCompanyStatsVO.CompanyItem();
            item.setCompanyId(first.getCompanyId());
            item.setCompanyName(first.getCompanyName());
            item.setCompanyAbbreviation(first.getCompanyAbbreviation());
            item.setLeafNode(first.getLeafNode());
            item.setDeviceCount(sumDeviceCount(companyRecords));
            item.setNodeCount(sumNodeCount(companyRecords));
            item.setNowValue(firstNonEmpty(companyRecords, ViewAccessDeviceList::getNowValue));
            item.setValueUnit(firstNonEmpty(companyRecords, ViewAccessDeviceList::getValueUnit));
            item.setMonitoringTime(formatTime(firstNonNull(companyRecords, ViewAccessDeviceList::getMonitoringTime)));
            item.setMnCode(firstNonEmpty(companyRecords, ViewAccessDeviceList::getMnCode));
            item.setMonitoringFactor(firstNonEmpty(companyRecords, ViewAccessDeviceList::getMonitoringFactor));
            item.setMonitoringName(firstNonEmpty(companyRecords, ViewAccessDeviceList::getMonitoringName));
            item.setContrastLabel(firstNonEmpty(companyRecords, ViewAccessDeviceList::getContrastLabel));
            result.add(item);
        }

        result.sort(Comparator.comparing(ViewAccessDeviceCompanyStatsVO.CompanyItem::getCompanyName, Comparator.nullsLast(String::compareTo)));
        return result;
    }

    /**
     * 基于companyName进行分组合并，相同companyName的数据合并为一条，数值字段相加
     */
    private List<ViewAccessDeviceCompanyStatsVO.CompanyItem> buildCompanyItemsByCompanyName(List<ViewAccessDeviceList> records) {
        if (records.isEmpty()) {
            return Collections.emptyList();
        }

        Map<String, List<ViewAccessDeviceList>> groupedByCompanyName = records.stream()
                .collect(Collectors.groupingBy(record -> {
                    String companyName = record.getCompanyName();
                    return hasText(companyName) ? companyName.trim() : "UNKNOWN_" + record.hashCode();
                }, LinkedHashMap::new, Collectors.toList()));

        List<ViewAccessDeviceCompanyStatsVO.CompanyItem> result = new ArrayList<>();
        for (List<ViewAccessDeviceList> companyRecords : groupedByCompanyName.values()) {
            if (companyRecords.isEmpty()) {
                continue;
            }
            ViewAccessDeviceCompanyStatsVO.CompanyItem item = new ViewAccessDeviceCompanyStatsVO.CompanyItem();
            item.setCompanyId(firstNonEmpty(companyRecords, ViewAccessDeviceList::getCompanyId));
            item.setCompanyName(firstNonEmpty(companyRecords, ViewAccessDeviceList::getCompanyName));
            item.setCompanyAbbreviation(firstNonEmpty(companyRecords, ViewAccessDeviceList::getCompanyAbbreviation));
            item.setLeafNode(firstNonEmpty(companyRecords, ViewAccessDeviceList::getLeafNode));
            // 数值字段相加
            item.setDeviceCount(sumDeviceCount(companyRecords));
            item.setNodeCount(sumNodeCount(companyRecords));
            item.setNowValue(firstNonEmpty(companyRecords, ViewAccessDeviceList::getNowValue));
            item.setValueUnit(firstNonEmpty(companyRecords, ViewAccessDeviceList::getValueUnit));
            item.setMonitoringTime(formatTime(firstNonNull(companyRecords, ViewAccessDeviceList::getMonitoringTime)));
            item.setMnCode(firstNonEmpty(companyRecords, ViewAccessDeviceList::getMnCode));
            item.setMonitoringFactor(firstNonEmpty(companyRecords, ViewAccessDeviceList::getMonitoringFactor));
            item.setMonitoringName(firstNonEmpty(companyRecords, ViewAccessDeviceList::getMonitoringName));
            item.setContrastLabel(firstNonEmpty(companyRecords, ViewAccessDeviceList::getContrastLabel));
            result.add(item);
        }

        result.sort(Comparator.comparing(ViewAccessDeviceCompanyStatsVO.CompanyItem::getDeviceCount, Comparator.nullsLast(Long::compareTo)).reversed());
        return result;
    }

    private long sumDeviceCount(List<ViewAccessDeviceList> records) {
        return records.stream()
                .map(ViewAccessDeviceList::getDeviceCount)
                .filter(Objects::nonNull)
                .mapToLong(Long::longValue)
                .sum();
    }

    private long sumNodeCount(List<ViewAccessDeviceList> records) {
        return records.stream()
                .map(ViewAccessDeviceList::getNodeCount)
                .filter(Objects::nonNull)
                .mapToLong(Long::longValue)
                .sum();
    }

    private <T> long distinctCount(List<ViewAccessDeviceList> records, Function<ViewAccessDeviceList, T> mapper) {
        return records.stream()
                .map(mapper)
                .filter(Objects::nonNull)
                .distinct()
                .count();
    }

    private long distinctCount(List<ViewAccessDeviceList> records, Function<ViewAccessDeviceList, String> mapper, Predicate<String> filter) {
        return records.stream()
                .map(mapper)
                .filter(value -> value != null && (filter == null || filter.test(value)))
                .map(String::trim)
                .filter(this::hasText)
                .distinct()
                .count();
    }

    private <T> T firstNonNull(List<ViewAccessDeviceList> records, Function<ViewAccessDeviceList, T> mapper) {
        for (ViewAccessDeviceList record : records) {
            T value = mapper.apply(record);
            if (value != null) {
                return value;
            }
        }
        return null;
    }

    private String firstNonEmpty(List<ViewAccessDeviceList> records, Function<ViewAccessDeviceList, String> mapper) {
        for (ViewAccessDeviceList record : records) {
            String value = mapper.apply(record);
            if (hasText(value)) {
                return value.trim();
            }
        }
        return null;
    }

    private String formatTime(LocalDateTime time) {
        if (time == null) {
            return null;
        }
        return DATE_TIME_FORMATTER.format(time);
    }

    private boolean hasText(String value) {
        return value != null && !value.trim().isEmpty();
    }

    /**
     * 判断字符串值是否为0
     */
    private boolean isZeroValue(String value) {
        if (value == null || value.trim().isEmpty()) {
            return false;
        }
        return true;
//        try {
//            String trimmed = value.trim();
//            // 尝试解析为 double，支持整数和小数
//            double numValue = Double.parseDouble(trimmed);
//            return numValue != 0.0;
//        } catch (NumberFormatException e) {
//            // 如果无法解析为数字，则不是0值
//            return true;
//        }
    }

    private String buildCompanyKey(ViewAccessDeviceList record) {
        if (record == null) {
            return "UNKNOWN";
        }
        if (hasText(record.getContrastLabel())) {
            return record.getContrastLabel().trim();
        }
        if (hasText(record.getCompanyName())) {
            return "NAME_" + record.getCompanyName().trim();
        }
        return "UNKNOWN_" + record.hashCode();
    }
}
